/*
 *  Copyright (C) 2011 JiangHongTiao <jjurco.sk_gmail.com>
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package sk.lieskove301.jianghongtiao.liaad.prisoner.statistics;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import sk.lieskove301.jianghongtiao.liaad.prisoner.agent.Agent;
import sk.lieskove301.jianghongtiao.liaad.prisoner.agent.AgentDescComparator;
import sk.lieskove301.jianghongtiao.liaad.prisoner.agent.AgentIncComparator;
import sk.lieskove301.jianghongtiao.liaad.prisoner.gene.GeneticInfo;
import sk.lieskove301.jianghongtiao.liaad.prisoner.memory.ForgettingEnum;

/**
 * Date of create: May 15, 2011
 *
 * @author JiangHongTiao <jjurco.sk_gmail.com>
 * @version 2011.0515
 */
public class StatisticStore {

    private List<Map<String, AgentsTimelineUnit>> allAgents =
            new ArrayList<Map<String, AgentsTimelineUnit>>();
    private List<Map<String, AgentsTimelineUnit>> newAgents =
            new ArrayList<Map<String, AgentsTimelineUnit>>();
    private List<Map<String, AgentsTimelineUnit>> deadAgents =
            new ArrayList<Map<String, AgentsTimelineUnit>>();
    private List<Map<String, AgentsTimelineUnit>> initialAgents =
            new ArrayList<Map<String, AgentsTimelineUnit>>();
    private List<Map<String, AgentsTimelineUnit>> finalAgents =
            new ArrayList<Map<String, AgentsTimelineUnit>>();

    //          Year         GeneticInfo  Agents
    private Map<Integer, Map<String, AgentsTimelineUnit>> best =
            new TreeMap<Integer, Map<String, AgentsTimelineUnit>>();

    private int bestN = 3;

    /**
     * store will remember all agents with the 3 highest scores
     */
    public StatisticStore() {
    }

    /**
     *
     * @param bestN remember all agents with best N scores
     */
    public StatisticStore(int bestN) {
        this.bestN = bestN;
    }

    public int getBestN() {
        return bestN;
    }

    public void setBestN(int bestN) {
        this.bestN = bestN;
    }

    
    private Map<String, AgentsTimelineUnit> rememberAgents(int year,
            List<Agent> agents){
        Map<String, AgentsTimelineUnit> map =
                new HashMap<String, AgentsTimelineUnit>();
        for (Iterator<Agent> it = agents.iterator(); it.hasNext();) {
            Agent agent = it.next();
            AgentsTimelineUnit timelineUnit = null;
            if(map.containsKey(agent.toString())){
                timelineUnit = map.get(agent.toString());
            } else {
                timelineUnit = new AgentsTimelineUnit();
                timelineUnit.setGeneticInfo(agent.toString());
                timelineUnit.setTime(year);
                timelineUnit.setBornYear(agent.getBirthday());
                timelineUnit.setInverted(agent.getInvert());
                timelineUnit.setOptimistic(agent.getOptimistic());
                timelineUnit.setMemory(agent.getForgetting());
            }
            timelineUnit.addScore(agent.getScore());
            timelineUnit.incCount();
            map.put(agent.toString(), timelineUnit);
        }
        //where.add(map);
        return map;
    }

    public void putAllAgents(int year, List<Agent> agents){
        allAgents.add(rememberAgents(year, agents));
    }

    public void putInitialAgents(int year, List<Agent> agents){
        initialAgents.add(rememberAgents(year, agents));
    }

    public void putFinalAgents(int year, List<Agent> agents){
        finalAgents.add(rememberAgents(year, agents));
    }

    public void putNewAgents(int year, List<Agent> agents){
        newAgents.add(rememberAgents(year, agents));
    }

    public void putDeadAgents(int year, List<Agent> agents){
        deadAgents.add(rememberAgents(year, agents));
    }

    public void rememberBest(int year, List<Agent> agents){
        Collections.sort(agents, new AgentDescComparator());
        double prevScore = Double.MAX_VALUE;
        int    numChanges = 0;
        List<Agent> bestNAgents = new ArrayList<Agent>();
        //for sorted agents
        for (Iterator<Agent> it = agents.iterator(); it.hasNext();) {
            //number of changes in score is out of scope
            if(numChanges > bestN) break;
            Agent agent = it.next();
            //if score was changed (at first time is always changed from MAX_VALUE)
            if(agent.getScore() < prevScore) {
                //increase number of changes
                numChanges++;
                //remember new score
                prevScore = agent.getScore();
            }
            //add agents with same score
            bestNAgents.add(agent);
        }
        //remember by year
        best.put(year, rememberAgents(year, bestNAgents));
    }

    public Map<Integer, Map<String, AgentsTimelineUnit>> getBest() {
        return best;
    }

    public List<Map<String, AgentsTimelineUnit>> getAllAgents() {
        return allAgents;
    }

    public List<Map<String, AgentsTimelineUnit>> getDeadAgents() {
        return deadAgents;
    }

    public List<Map<String, AgentsTimelineUnit>> getFinalAgents() {
        return finalAgents;
    }

    public List<Map<String, AgentsTimelineUnit>> getInitialAgents() {
        return initialAgents;
    }

    public List<Map<String, AgentsTimelineUnit>> getNewAgents() {
        return newAgents;
    }


}
